#pragma once 
#include <cstdint>
#include <iostream>
#include <memory>
#include <sys/epoll.h>
#include <unordered_map>
#include "Epoller.hpp"
#include "Connection.hpp"
#include "Log.hpp"
using namespace LogModule;
class Reactor {
    const static int num = 128;
private:
    bool IsConnectionExistsHelper(int sockfd)
    {
        auto it = _connections.find(sockfd);
        if(it == _connections.end()) {
            return false;
        }else {
            return true;
        }
    }
    bool IsConnectionExists(const std::shared_ptr<Connection> &conn)
    {
        return IsConnectionExistsHelper(conn->GetSockFd());
    }
    bool IsConnectionExists(int sockfd)
    {
        return IsConnectionExistsHelper(sockfd);
    }
    bool IsConnectionEmpty()
    {   
        return _connections.empty();
    }
    int LoopOnce(int timeout)
    {
        return _epoller_ptr->WaitEvents(_revs, num, timeout);
    }
    void Dispatcher(int n) {
        for(int i = 0; i < n; i++) {
            int sockfd = _revs[i].data.fd;
            uint32_t revents = _revs[i].events;
            if(revents & EPOLLERR) { // 错误
                revents |= (EPOLLIN | EPOLLOUT);
            }
            if(revents & EPOLLHUP) { // 挂起
                revents |= (EPOLLIN | EPOLLOUT); // 直接交给下层自动报错处理即可
            }
            if(EPOLLIN & revents) {
                if(IsConnectionExists(sockfd)) {
                    _connections[sockfd]->Recver();
                }
            }
            if(EPOLLOUT & revents) {
                if(IsConnectionExists(sockfd)) {
                    _connections[sockfd]->Sender();
                }
            }
        }
    }
public:
    Reactor() : _epoller_ptr(std::make_unique<Epoller>()), _isrunning(false) {}
    void Loop() {
        if(IsConnectionEmpty()) {
            return;
        }
        _isrunning = true;
        int timeout = -1;
        while (_isrunning) {
            PrintConnection();
            int n = LoopOnce(timeout);
            Dispatcher(n);
        }
        _isrunning = false;
    }
    void AddConnection(std::shared_ptr<Connection>& conn) {
        if(IsConnectionExists(conn)) {
            return;
        }
        uint32_t events = conn->GetEvent();
        int sockfd = conn->GetSockFd();
        _epoller_ptr->AddEvent(sockfd, events);
        conn->SetOwner(this);
        _connections[sockfd] = conn;
    }
    void EnableReadWrite(int sockfd, bool EnableRead, bool EnableWrite) {
        if(!IsConnectionExists(sockfd)) {
            LOG(LogLevel::WARNING) << "have exixted, sockfd : " << sockfd;
            return;
        }
        uint32_t new_event = (EPOLLET | (EnableRead ? EPOLLIN : 0) | (EnableWrite ? EPOLLOUT : 0));
        _connections[sockfd]->SetEvent(new_event);
        _epoller_ptr->ModEvent(sockfd, new_event);
    }
    void DelConnection(int sockfd) {
        _epoller_ptr->DelEvent(sockfd);
        _connections.erase(sockfd);
        close(sockfd);
        LOG(LogLevel::INFO) << "client quit, sockfd :" << sockfd;
    }
    void PrintConnection() {
        std::cout << "当前管理的fd: ";
        for(auto& conn : _connections) {
            std::cout << conn.second << " ";
        }
        std::cout << endl;
    }
    ~Reactor() {}
private:
    std::unique_ptr<Epoller> _epoller_ptr; // IO多路复用的底层工具
    bool _isrunning;
    std::unordered_map<int, std::shared_ptr<Connection>> _connections; // 管理连接（包括监听和accept后的）
    struct epoll_event _revs[num];
};